package com.briup.day20;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.*;

public class Homework2 {
    public static void main(String[] args) throws IOException {
        test();
    }

    private static void test2() {
        // 使用10个线程，向ArrayList中添加10万个元素
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
//        ArrayList<Integer> integers = new ArrayList<>();
        Vector<Integer> integers = new Vector<>();
        Callable<Integer> task = () -> {
            for (int i = 0; i < 10000; i++) {
                integers.add(i);
            }
            // 元素添加结束后，返回该集合的大小
            return integers.size();
        };
        // 分配10个线程执行添加元素的任务
        for (int i = 0; i < 10; i++) {
            threadPool.submit(task);
        }

        // 等待线程池执行完毕后获取集合中元素的个数
        threadPool.shutdown();
        // 如果线程池没有关闭，那么isTerminated()返回的结果为false
        // 如果执行万shutdown()方法后，会等线程池中现有的所有任务都执行完毕后，将线程池进行关闭
        // 此时isTerminated()返回的结果就会变为true
        while (!threadPool.isTerminated()) {
        }

        // 获取元素的个数
        System.out.println("当前集合中元素的个数:" + integers.size());
    }

    private static void test() throws IOException {
        // 售票，4个窗口出售50张票
        // 创建售票任务
        TicketSaler ticketSaler = new TicketSaler();
        // 使用线程池维护
        // 使用Executors线程池工具类，调用其内部的newFixedThreadPool()方法，
        // 即可快速的创建出一个核心线程数以及最大线程数为4的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 4; i++) {
            // execute()方法只是单纯的分发一个线程执行任务，没有返回值，在外不能监测任务的执行状态
            // submit()方法可以传入Runnable接口和Callable接口的实现类对象，
            // 并且该方法存在一个Future接口实现类对象作为返回值，可以通过该对象获取到任务的执行结果，
            // 以及监测该任务的执行状态
            Future<?> submit = threadPool.submit(ticketSaler);
        }

        // 及时把线程池关闭
        threadPool.shutdown();
    }
}

class TicketSaler implements Runnable {
    // 维护一个用于表示余票的属性
    private int tickets = 50;
    // 维护一个用于记录售票数量的属性
    private int count;
    private final static Random RANDOM = new Random();
    private final FileWriter fw;

    public TicketSaler() throws IOException {
        fw = new FileWriter("resource/a.txt", true);
    }

    @Override
    public void run() {
        // 将50张票进行出售
        while (count <= 50 && tickets > 0) {
            String name = Thread.currentThread().getName();
            // 休眠100，200毫秒，模拟实际的出票场景
            try {
                // 保证以下代码是线程同步的，可以给下列代码进行上锁
                // synchronized是用于同步锁的关键字，可以给代码块、方法进行上锁
                // 在给代码块进行上锁时，锁对象需要你进行指定；
                // 注意如果要让所有的线程都保证同步，那么所有线程的锁对象都必须是同一个
                synchronized (this) {
                    if (tickets > 0) {
                        String s = String.format("当前%s正在出售第%s张票，还剩余票%s%n", name, ++count, --tickets);
                        // 将数据写出到文件中
                        fw.write(s);
                        fw.flush();
                        // sleep()方法导致的休眠，不会释放锁资源，抱着锁资源一起休眠
                        Thread.sleep(RANDOM.nextInt(100, 201));
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}